package org.fhawk.tinyspring.aop.proxy;

import org.fhawk.tinyspring.exception.ProxyException;
import org.fhawk.tinyspring.ioc.BeanHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * Created by tuo on 10/9/16.
 */
public class ProxyManager implements InvocationHandler {
    private Logger logger = LoggerFactory.getLogger(ProxyManager.class);
    private Object instance;
    private List<? extends Proxy> proxies;

    public Object newInstance(Class<?> target, List<Class<? extends Proxy>> proxyList) {
        logger.debug("处理{}的代理", target);
        instance = BeanHelper.getBean(target);
        Object proxyInstance = java.lang.reflect.Proxy.newProxyInstance(ProxyManager.class.getClassLoader(), target.getInterfaces(), new ProxyManager());
        proxies = proxyList.stream().map(clazz -> {
            try {
                return clazz.newInstance();
            } catch (Exception e) {
                logger.error("获取类实例失败。", e);
            }
            return null;
        }).filter(Objects::nonNull).collect(Collectors.toList());
        return proxyInstance;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = null;
        try {
            proxies.forEach(p -> {
                try {
                    p.doBefore(method);
                } catch (ProxyException e) {
                    logger.error("代理前置处理失败。", e);
                }
            });
            result = method.invoke(instance, args);
            proxies.forEach(p -> {
                try {
                    p.doAfter(method);
                } catch (ProxyException e) {
                    logger.error("代理后置处理失败。", e);
                }
            });
        } catch (Exception e) {
            proxies.forEach(p -> {
                try {
                    p.doThrowable(method, e);
                } catch (ProxyException e1) {
                    logger.error("代理异常处理失败。", e);
                }
            });
        } finally {
            proxies.forEach(p -> p.doFinally(method));
        }
        return result;
    }
}
